package com.bxl.netty.rpc.register.server;


import com.bxl.netty.rpc.client.common.client.ClientInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 滑动窗口统计心跳次数。定时任务控制 index 定时增长。
 *
 * @author baixl
 * @date 2021/3/5
 */
public class SlidingWindow {
    private int length;
    private int index;
    private int inteval;
    private Map<ClientInfo, Integer>[] windows;
    private ScheduledExecutorService executorService;
    private TimeUnit timeUnit;


    public SlidingWindow(int length, int inteval, TimeUnit timeUnit) {
        this.length = length + 1;
        this.inteval = inteval;
        this.timeUnit = timeUnit;
    }

    public void init() {
        windows = new Map[length];
        for (int i = 0; i < length; i++) {
            windows[i] = new ConcurrentHashMap();
        }
        index = 0;
        executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread a = new Thread(r);
                a.setDaemon(true);
                a.setName("SlidingWindow-1");
                return a;
            }
        });

        executorService.scheduleAtFixedRate(new Runnable() {
            public void run() {
                if (index >= (length - 1)) {
                    index = 0;
                } else {
                    index++;
                }
                windows[index].clear();
            }
        }, this.inteval, this.inteval, this.timeUnit);
    }

    /**
     * 客户端注册的时候采用单线程循环注册
     *
     * @param client
     */
    public void register(ClientInfo client) {
        Integer curNum = windows[index].get(client);
        if (curNum == null) {
            windows[index].put(client, 1);
        } else {
            windows[index].put(client, curNum + 1);
        }
    }

    /**
     * 统计时间段内的注册次数-暂时只考虑ip和端口
     *
     * @param client
     * @return
     */
    public int stts(ClientInfo client) {
        int tempIndex = index;
        int tempLength = length - 1;
        int sum = 0;
        for (int i = 0; i < tempLength; i++) {
            if (windows[tempIndex].get(client) != null) {
                sum += windows[tempIndex].get(client);
            }
            if (tempIndex == 0) {
                tempIndex = tempLength;
            } else {
                tempIndex--;
            }
        }
        return sum;
    }
    
    public List<ClientInfo> sttsAll(){
        List<ClientInfo>  allRegister = new ArrayList<ClientInfo>();
        List<ClientInfo>  rtn = new ArrayList<ClientInfo>();
        int tempIndex = index;
        int tempLength = length - 1;
        for (int i = 0; i < tempLength; i++) {
            allRegister.addAll(windows[tempIndex].keySet());
            if (tempIndex == 0) {
                tempIndex = tempLength;
            } else {
                tempIndex--;
            }
        }
        for (ClientInfo clientInfo : allRegister) {
            if(!rtn.contains(clientInfo)){
                rtn.add(clientInfo); 
            }
        }
        
        return rtn;
    }
}
